home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!uunet!munnari.oz.au!metro!cluster!swift!sunaus.oz!newstop!exodus!rand.org
- From: bobs@rand.org (Rober Schwartzkopf)
- Newsgroups: comp.sources.x
- Subject: v13i056: xmeter, Patch6, Part01/01
- Message-ID: <15395@exodus.Eng.Sun.COM>
- Date: 18 Jun 91 06:42:17 GMT
- References: <csx-13i056-xmeter@uunet.UU.NET>
- Sender: news@exodus.Eng.Sun.COM
- Lines: 1967
- Approved: argv@sun.com
-
- Submitted-by: Rober Schwartzkopf <bobs@rand.org>
- Posting-number: Volume 13, Issue 56
- Archive-name: xmeter/patch6
- Patch-To: xmeter: Volume 9, Issue 59 (9/28/90)
-
- This is xmeter patchlevel 6. Changes since the previous release
- include new option (-v) to print xmeter version, defstat option to
- change the default statistic to be watched, clearing of stripchart
- widgets when watched stat is changed, and better handling of dead
- hosts, as well as a couple of minor bug fixes.
-
- Bob Schwartzkopf (bobs@rand.org)
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: patchlevel.h README Imakefile xmeter.c xmeter.man
- # XMeter.ad
- # Wrapped by root@boris on Mon Jun 3 15:27:22 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'patchlevel.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'patchlevel.h'\"
- else
- echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
- sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
- X#define PATCHLEVEL 6
- END_OF_FILE
- if test 21 -ne `wc -c <'patchlevel.h'`; then
- echo shar: \"'patchlevel.h'\" unpacked with wrong size!
- fi
- # end of 'patchlevel.h'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(1879 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- Xxmeter displays a histogram of data returned by rstat(3). It can be
- Xtold to monitor multiple hosts, or to monitor multiple statistics on the
- Xsame host.
- X
- XAuthor: Bob Schwartzkopf (bobs@rand.org)
- X The RAND Corporation
- X 1700 Main Street
- X Santa Monica, CA 90406-2138
- X
- XEdit history
- X
- XPatchlevel 6
- X - Clear stripcharts when monitored statistic is changed.
- X - Allow setting of monitored stat in .Xdefaults.
- X - Added -v option to display version number.
- X - Fork new process to wait for dead host to come back up.
- X
- XPatchlevel 5
- X - Put explict closes of sockets back in after clnt_destroy().
- X Apparently some versions of clnt_destroy don't close the
- X socket.
- X - Minor changes to XMeter.ad.
- X
- XPatchlevel 4
- X - Allow user to specify foreground, border, internal border and
- X highlight color for each level.
- X - Fixed bug in determining width/height of form widget.
- X - Allow user to specify label foreground and background colors
- X independently of stripcharts.
- X - Made all colors either class Foreground or Background, should
- X simplify .Xdefaults files.
- X
- XPatchlevel 3
- X - Added "cols" and "rows" options, allows rectangular
- X layout of graphs. Removed "orientation" option.
- X - Backgrounds of stripcharts can now be set to user specified
- X bitmaps with "*Bitmap" resources.
- X - Added op, wp, ep and fp options, which takes a program name as an
- X argument. When a graph enters state OK, WARN, ERROR or FATAL, the
- X specified program is invoked.
- X - Added menus which allow the monitored statistic to be changed
- X on the fly.
- X
- XPatchlevel 2
- X - Changed resource name of paned widgets to host name.
- X - Used actual time between rstat(3) calls instead of "update"
- X interval for computing graph values.
- X - Rewrote functions that return graph values.
- X - Fixed divide by 0 errors in fcpu(), fsys() and fuser().
- X - Use RSTATVERS_TIME instead of RSTATVERS.
- X
- XPatchlevel 1
- X - Fixed memory leak.
- END_OF_FILE
- if test 1879 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'Imakefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Imakefile'\"
- else
- echo shar: Extracting \"'Imakefile'\" \(369 characters\)
- sed "s/^X//" >'Imakefile' <<'END_OF_FILE'
- X INCLUDES = -I$(TOP) -I$(TOP)/X11
- X DEPLIBS = XawClientDepLibs
- XLOCAL_LIBRARIES = XawClientLibs
- X SYS_LIBRARIES = -lrpcsvc
- X SRCS = xmeter.c
- X OBJS = xmeter.o
- X SHARS = patchlevel.h README Imakefile xmeter.c xmeter.man XMeter.ad
- X
- XComplexProgramTarget(xmeter)
- XInstallAppDefaults(XMeter)
- X
- Xxmeter.shar: $(SHARS)
- X shar -o xmeter.shar $(SHARS)
- END_OF_FILE
- if test 369 -ne `wc -c <'Imakefile'`; then
- echo shar: \"'Imakefile'\" unpacked with wrong size!
- fi
- # end of 'Imakefile'
- fi
- if test -f 'xmeter.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xmeter.c'\"
- else
- echo shar: Extracting \"'xmeter.c'\" \(33499 characters\)
- sed "s/^X//" >'xmeter.c' <<'END_OF_FILE'
- X/*
- X * xmeter.c - Display histogram of rstat(3) output for multiple hosts.
- X *
- X * Author: Bob Schwartzkopf, The RAND Corporation
- X *
- X * Suggestions for improvements and bug fixes can be sent to "bobs@rand.org".
- X * As my schedule permits I'll try to incorporate them.
- X */
- X
- X#ifndef lint
- Xstatic char *RCSid="$Header: /usr/rand/src/bin/xmeter/RCS/xmeter.c,v 1.7 1991/06/03 22:21:43 root Exp $";
- X#endif lint
- X
- X/*
- X * $Log: xmeter.c,v $
- X * Revision 1.7 1991/06/03 22:21:43 root
- X * Add -v option to print xmeter version number.
- X * Add defstat option.
- X * Add code to clear stripchart when watched stat is changed.
- X * When host is down fork process to wait for it to come up instead of
- X * having toplevel process wait for timeouts.
- X *
- X * Revision 1.6 90/09/28 20:32:34 root
- X * Add explicit closes of sockets back in, apparently some versions of
- X * clnt_destroy() don't do it automatically.
- X *
- X * Revision 1.5 90/09/18 20:47:03 root
- X * Allow user specification of foreground colors.
- X *
- X * Revision 1.4 90/08/20 14:18:01 root
- X * Added menus, column and row options, background bitmaps, and user
- X * specifiable programs to be invoked when graphs change state.
- X *
- X * Revision 1.3 90/06/07 16:17:06 bobs
- X * Removed "retries".
- X * Changed name of paned widgets to host name displayed in that widget.
- X * Used actual time between rstat calls instead of "update" interval in
- X * computing rates in functions that return values to stripchart widgets.
- X * Removed "ost" variable, rewrote functions that return values to
- X * stripcharts.
- X * Fixed bug in fsys, fcpu and fuser that could cause divide by 0 errors.
- X * Fixed rpc timeout handling in getmeter and getport.
- X * Use RSTATVERS_TIME instead of RSTATVERS, which isn't defined in SunOS 4.1.
- X *
- X * Revision 1.2 90/05/04 12:31:52 bobs
- X * Fix memory leak in getport(). Wasn't freeing resources allocated by
- X * clntudp_create when clnt_call failed. Also removed explicit calls
- X * to close sockets since clnt_destroy() does this.
- X *
- X * Revision 1.1 90/04/30 14:33:59 bobs
- X * Initial revision
- X *
- X */
- X
- X#include <stdio.h>
- X#include <sys/time.h>
- X#include <sys/param.h>
- X#include <sys/socket.h>
- X#include <sys/dk.h>
- X#include <signal.h>
- X#include <netdb.h>
- X#include <rpc/rpc.h>
- X#include <rpc/pmap_prot.h>
- X#include <rpcsvc/rstat.h>
- X#include <X11/Xlib.h>
- X#include <X11/Intrinsic.h>
- X#include <X11/StringDefs.h>
- X#include <X11/Xatom.h>
- X#include <X11/Shell.h>
- X#include <X11/Xaw/Cardinals.h>
- X#include <X11/Xaw/Form.h>
- X#include <X11/Xaw/StripChart.h>
- X#include <X11/Xaw/SimpleMenu.h>
- X#include <X11/Xaw/MenuButton.h>
- X#include <X11/Xaw/SmeBSB.h>
- X#include <X11/Xaw/Paned.h>
- X#include <X11/Xmu/Xmu.h>
- X#include "patchlevel.h"
- X
- X#define MAJORVERSION 1
- X#define DMSG "down"
- X#define OK 0
- X#define WARN 1
- X#define ERROR 2
- X#define FATAL 3
- X#define MAXBACKS (FATAL+1)
- X#define STATMENU "statmenu"
- X#ifndef FSCALE
- X#define FSCALE (1 << 8)
- X#endif
- X
- X/*
- X * There is one METER structure per strip chart. If multiple stats
- X * on a single host are being watched we save rstatd calls by sharing
- X * part of this structure (SHMETER) between the different meters watching
- X * the same host.
- X */
- Xtypedef struct _shmeter {
- X char *name; /* Host name */
- X struct sockaddr_in addr;
- X CLIENT *clnt;
- X int s; /* Socket */
- X struct statstime st[2]; /* Keep last 2 stats to compute diffs */
- X int idx; /* Index into st array */
- X int refcnt; /* Meters sharing this structure */
- X int curcnt; /* Meters who've displayed current data */
- X int first; /* TRUE when only 1 rstat has been done */
- X int pid; /* Pid of proc waiting for host */
- X struct _shmeter *nxt; /* Link these together */
- X} SHMETER;
- X
- Xtypedef struct _meter {
- X char *label;
- X int stat; /* Which stat to watch */
- X Widget pdwidget; /* Paned widget */
- X Widget mbwidget; /* MenuButton widget */
- X Widget scwidget; /* StripChart widget */
- X int oldstate; /* Save state so know when to */
- X /* change backgrounds */
- X SHMETER *sh; /* Shared info */
- X Pixmap pm; /* Current background pixmap */
- X int oldjumpscroll; /* Old jumpscroll value */
- X struct _meter *nxt;
- X} METER;
- X
- X/*
- X * There is a STATDATA structure for each statistic that can be monitored.
- X */
- Xtypedef struct {
- X int scale; /* Each stat is scaled */
- X int (*val)(); /* Function that computes this stat */
- X char *name; /* Name of stat for menu widget */
- X} STATDATA;
- X
- X/*
- X * xmeter supports 4 background colors and pixmaps that it will switch
- X * between as a meter changes state, called OK, WARN, ERROR and FATAL.
- X * The background bitmaps are stored in BITMAP structures.
- X */
- Xtypedef struct {
- X int w; /* Width of bitmap */
- X int h; /* Height of bitmap */
- X Pixmap bm; /* Bitmap */
- X} BITMAP;
- X
- X/*
- X * Functions
- X */
- Xextern char *malloc ();
- Xextern char *index ();
- Xint getstatus ();
- Xint changestat ();
- Xint selecthost ();
- Xint freechild ();
- XMETER *initmeter ();
- Xint fcoll (), fcpu (), fierr (), fintr (), fipkt (), fload ();
- Xint foerr (), fopkt (), fpage (), fpgpgin (), fpgpgout ();
- Xint fpswpin (), fpswpout (), fswt (), fsys (), fuser ();
- X
- XSTATDATA sd[] = {
- X#define S_COLL 0
- X {1, fcoll, "coll"},
- X#define S_CPU S_COLL+1
- X {1, fcpu, "cpu"},
- X#define S_IERR S_CPU+1
- X {1, fierr, "ierr"},
- X#define S_INTR S_IERR+1
- X {1, fintr, "intr"},
- X#define S_IPKT S_INTR+1
- X {1, fipkt, "ipkt"},
- X#define S_LOAD S_IPKT+1
- X {1, fload, "load"},
- X#define S_OERR S_LOAD+1
- X {1, foerr, "oerr"},
- X#define S_OPKT S_OERR+1
- X {1, fopkt, "opkt"},
- X#define S_PAGE S_OPKT+1
- X {1, fpage, "page"},
- X#define S_PGPGIN S_PAGE+1
- X {1, fpgpgin, "pgpgin"},
- X#define S_PGPGOUT S_PGPGIN+1
- X {1, fpgpgout, "pgpgout"},
- X#define S_PSWPIN S_PGPGOUT+1
- X {1, fpswpin, "pswpin"},
- X#define S_PSWPOUT S_PSWPIN+1
- X {1, fpswpout, "pswpout"},
- X#define S_SWT S_PSWPOUT+1
- X {1, fswt, "swt"},
- X#define S_SYS S_SWT+1
- X {1, fsys, "sys"},
- X#define S_USER S_SYS+1
- X {1, fuser, "user"},
- X};
- X#define DEFSTATNAME "load"
- X#define MAXSTAT (sizeof (sd) / sizeof (STATDATA))
- X#define MAXSTATNAME 10 /* Max length of stat name */
- X
- Xstatic char *progname;
- XPixel back[MAXBACKS]; /* Meter backgrounds */
- XPixel fore[MAXBACKS]; /* Meter foregrounds */
- XPixel hl[MAXBACKS]; /* Meter highlights */
- XPixel bd[MAXBACKS]; /* Meter borders */
- XPixel ibd[MAXBACKS]; /* Meter internal bds */
- XPixel lback[MAXBACKS]; /* Label backgrounds */
- XPixel lfore[MAXBACKS]; /* Label foregrounds */
- XBITMAP bitmap[MAXBACKS]; /* Stripchart bg pixmaps*/
- XPixmap bitmapdef = XtUnspecifiedPixmap;
- Xint warnLevel; /* Warning level */
- Xint errorLevel; /* Error level */
- Xstatic struct timeval ptto = {0, 0}; /* RPC timeout interval */
- Xstatic struct timeval tto = {0, 0}; /* Total timeout */
- Xstatic SHMETER *shmeters = NULL; /* List of SHMETERs */
- Xstatic METER *selected; /* Current meter */
- Xstatic METER *meterlist = NULL; /* List of METERs */
- Xint columns; /* Columns to display */
- Xint rows; /* Rows to display */
- Xint timeout; /* RPC timeout */
- Xint retries; /* RPC retries */
- Xint loadscaledef = FSCALE; /* Scale for load ave. */
- XBoolean shortname; /* Short hostname flag */
- XString prog[MAXBACKS]; /* Alert programs */
- XString defstat; /* Default stat */
- Xstatic XtResource application_resources[] = {
- X {"columns", "Columns", XtRInt, sizeof (int),
- X (Cardinal) &columns, XtRString, "0"},
- X {"defStat", "DefStat", XtRString, sizeof (char *),
- X (Cardinal) &defstat, XtRString, DEFSTATNAME},
- X {"errorBack", XtCBackground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &back[ERROR], XtRString, XtDefaultBackground},
- X {"errorBd", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &bd[ERROR], XtRString, XtDefaultForeground},
- X {"errorBitmap", XtCBitmap, XtRBitmap, sizeof (Pixmap),
- X (Cardinal) &bitmap[ERROR].bm, XtRBitmap, (caddr_t) &bitmapdef},
- X {"errorFore", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &fore[ERROR], XtRString, XtDefaultForeground},
- X {"errorHl", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &hl[ERROR], XtRString, XtDefaultForeground},
- X {"errorIbd", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &ibd[ERROR], XtRString, XtDefaultForeground},
- X {"errorLevel", "ErrorLevel", XtRInt, sizeof (int),
- X (Cardinal) &errorLevel, XtRString, "6"},
- X {"errorProg", "Program", XtRString, sizeof (char *),
- X (Cardinal) &prog[ERROR], XtRString, NULL},
- X {"fatalBack", XtCBackground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &back[FATAL], XtRString, XtDefaultBackground},
- X {"fatalBd", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &bd[FATAL], XtRString, XtDefaultForeground},
- X {"fatalBitmap", XtCBitmap, XtRBitmap, sizeof (Pixmap),
- X (Cardinal) &bitmap[FATAL].bm, XtRBitmap, (caddr_t) &bitmapdef},
- X {"fatalFore", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &fore[FATAL], XtRString, XtDefaultForeground},
- X {"fatalHl", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &hl[FATAL], XtRString, XtDefaultForeground},
- X {"fatalIbd", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &ibd[FATAL], XtRString, XtDefaultForeground},
- X {"fatalProg", "Program", XtRString, sizeof (char *),
- X (Cardinal) &prog[FATAL], XtRString, NULL},
- X {"lErrorBack", XtCBackground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &lback[ERROR], XtRString, XtDefaultBackground},
- X {"lErrorFore", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &lfore[ERROR], XtRString, XtDefaultForeground},
- X {"lFatalBack", XtCBackground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &lback[FATAL], XtRString, XtDefaultBackground},
- X {"lFatalFore", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &lfore[FATAL], XtRString, XtDefaultForeground},
- X {"lOkBack", XtCBackground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &lback[OK], XtRString, XtDefaultBackground},
- X {"lOkFore", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &lfore[OK], XtRString, XtDefaultForeground},
- X {"lWarnBack", XtCBackground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &lback[WARN], XtRString, XtDefaultBackground},
- X {"lWarnFore", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &lfore[WARN], XtRString, XtDefaultForeground},
- X {"okBack", XtCBackground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &back[OK], XtRString, XtDefaultBackground},
- X {"okBd", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &bd[OK], XtRString, XtDefaultForeground},
- X {"okBitmap", XtCBitmap, XtRBitmap, sizeof (Pixmap),
- X (Cardinal) &bitmap[OK].bm, XtRBitmap, (caddr_t) &bitmapdef},
- X {"okFore", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &fore[OK], XtRString, XtDefaultForeground},
- X {"okHl", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &hl[OK], XtRString, XtDefaultForeground},
- X {"okIbd", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &ibd[OK], XtRString, XtDefaultForeground},
- X {"okProg", "Program", XtRString, sizeof (char *),
- X (Cardinal) &prog[OK], XtRString, NULL},
- X {"retries", "Retries", XtRInt, sizeof (int),
- X (Cardinal) &retries, XtRString, "2"},
- X {"rows", "Rows", XtRInt, sizeof (int),
- X (Cardinal) &rows, XtRString, "0"},
- X {"scaleColl", "ScaleColl", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_COLL].scale, XtRString, "1"},
- X {"scaleCpu", "ScaleCpu", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_CPU].scale, XtRString, "20"},
- X {"scaleIerr", "ScaleIerr", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_IERR].scale, XtRString, "1"},
- X {"scaleIntr", "ScaleIntr", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_INTR].scale, XtRString, "50"},
- X {"scaleIpkt", "ScaleIpkt", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_IPKT].scale, XtRString, "20"},
- X {"scaleLoad", "ScaleLoad", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_LOAD].scale, XtRInt, (caddr_t) &loadscaledef},
- X {"scaleOerr", "ScaleOerr", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_OERR].scale, XtRString, "1"},
- X {"scaleOpkt", "ScaleOpkt", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_OPKT].scale, XtRString, "20"},
- X {"scalePage", "ScalePage", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_PAGE].scale, XtRString, "10"},
- X {"scalePgpgin", "ScalePgpgin", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_PGPGIN].scale, XtRString, "10"},
- X {"scalePgpgout", "ScalePgpgout", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_PGPGOUT].scale, XtRString, "10"},
- X {"scalePswpin", "ScalePswpin", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_PSWPIN].scale, XtRString, "1"},
- X {"scalePswpout", "ScalePswpout", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_PSWPOUT].scale, XtRString, "1"},
- X {"scaleSwt", "ScaleSwt", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_SWT].scale, XtRString, "30"},
- X {"scaleSys", "ScaleSys", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_SYS].scale, XtRString, "20"},
- X {"scaleUser", "ScaleUser", XtRInt, sizeof (int),
- X (Cardinal) &sd[S_USER].scale, XtRString, "20"},
- X {"shortName", "Shortname", XtRBoolean, sizeof (Boolean),
- X (Cardinal) &shortname, XtRString, "False"},
- X {"timeout", "Timeout", XtRInt, sizeof (int),
- X (Cardinal) &timeout, XtRString, "5"},
- X {"warnBack", XtCBackground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &back[WARN], XtRString, XtDefaultBackground},
- X {"warnBd", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &bd[WARN], XtRString, XtDefaultForeground},
- X {"warnBitmap", XtCBitmap, XtRBitmap, sizeof (Pixmap),
- X (Cardinal) &bitmap[WARN].bm, XtRBitmap, (caddr_t) &bitmapdef},
- X {"warnFore", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &fore[WARN], XtRString, XtDefaultForeground},
- X {"warnHl", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &hl[WARN], XtRString, XtDefaultForeground},
- X {"warnIbd", XtCForeground, XtRPixel, sizeof (Pixel),
- X (Cardinal) &ibd[WARN], XtRString, XtDefaultForeground},
- X {"warnLevel", "WarnLevel", XtRInt, sizeof (int),
- X (Cardinal) &warnLevel, XtRString, "3"},
- X {"warnProg", "Program", XtRString, sizeof (char *),
- X (Cardinal) &prog[WARN], XtRString, NULL},
- X};
- Xstatic XrmOptionDescRec options[] = {
- X {"-cols", "columns", XrmoptionSepArg, NULL},
- X {"-ebd", "errorBd", XrmoptionSepArg, NULL},
- X {"-ebg", "errorBack", XrmoptionSepArg, NULL},
- X {"-efg", "errorFore", XrmoptionSepArg, NULL},
- X {"-ehl", "errorHl", XrmoptionSepArg, NULL},
- X {"-eibd", "errorIbd", XrmoptionSepArg, NULL},
- X {"-elevel", "errorLevel", XrmoptionSepArg, NULL},
- X {"-ep", "errorProg", XrmoptionSepArg, NULL},
- X {"-fbd", "fatalBd", XrmoptionSepArg, NULL},
- X {"-fbg", "fatalBack", XrmoptionSepArg, NULL},
- X {"-ffg", "fatalFore", XrmoptionSepArg, NULL},
- X {"-fhl", "fatalHl", XrmoptionSepArg, NULL},
- X {"-fibd", "fatalIbd", XrmoptionSepArg, NULL},
- X {"-fp", "fatalProg", XrmoptionSepArg, NULL},
- X {"-h", "*Paned.height", XrmoptionSepArg, NULL},
- X {"-lebg", "lErrorBack", XrmoptionSepArg, NULL},
- X {"-lefg", "lErrorFore", XrmoptionSepArg, NULL},
- X {"-lfbg", "lFatalBack", XrmoptionSepArg, NULL},
- X {"-lffg", "lFatalFore", XrmoptionSepArg, NULL},
- X {"-lobg", "lOkBack", XrmoptionSepArg, NULL},
- X {"-lofg", "lOkFore", XrmoptionSepArg, NULL},
- X {"-lwbg", "lWarnBack", XrmoptionSepArg, NULL},
- X {"-lwfg", "lWarnFore", XrmoptionSepArg, NULL},
- X {"-obd", "okBd", XrmoptionSepArg, NULL},
- X {"-obg", "okBack", XrmoptionSepArg, NULL},
- X {"-ofg", "okFore", XrmoptionSepArg, NULL},
- X {"-ohl", "okHl", XrmoptionSepArg, NULL},
- X {"-oibd", "okIbd", XrmoptionSepArg, NULL},
- X {"-op", "okProg", XrmoptionSepArg, NULL},
- X {"-rows", "rows", XrmoptionSepArg, NULL},
- X {"-rt", "retries", XrmoptionSepArg, NULL},
- X {"-scoll", "scaleColl", XrmoptionSepArg, NULL},
- X {"-scpu", "scaleCpu", XrmoptionSepArg, NULL},
- X {"-sierr", "scaleIerr", XrmoptionSepArg, NULL},
- X {"-sintr", "scaleIntr", XrmoptionSepArg, NULL},
- X {"-sipkt", "scaleIpkt", XrmoptionSepArg, NULL},
- X {"-sload", "scaleLoad", XrmoptionSepArg, NULL},
- X {"-sn", "shortName", XrmoptionNoArg, "on"},
- X {"-soerr", "scaleOerr", XrmoptionSepArg, NULL},
- X {"-sopkt", "scaleOpkt", XrmoptionSepArg, NULL},
- X {"-spage", "scalePage", XrmoptionSepArg, NULL},
- X {"-spgpgin", "scalePgpgin", XrmoptionSepArg, NULL},
- X {"-spgpgout", "scalePgpgout", XrmoptionSepArg, NULL},
- X {"-spswpin", "scalePswpin", XrmoptionSepArg, NULL},
- X {"-spswpout", "scalePswpout", XrmoptionSepArg, NULL},
- X {"-sswt", "scaleSwt", XrmoptionSepArg, NULL},
- X {"-ssys", "scaleSys", XrmoptionSepArg, NULL},
- X {"-suser", "scaleUser", XrmoptionSepArg, NULL},
- X {"-to", "timeout", XrmoptionSepArg, NULL},
- X {"-update", "*StripChart.update", XrmoptionSepArg, NULL},
- X {"-w", "*Paned.width", XrmoptionSepArg, NULL},
- X {"-wbd", "warnBd", XrmoptionSepArg, NULL},
- X {"-wbg", "warnBack", XrmoptionSepArg, NULL},
- X {"-wfg", "warnFore", XrmoptionSepArg, NULL},
- X {"-whl", "warnHl", XrmoptionSepArg, NULL},
- X {"-wibd", "warnIbd", XrmoptionSepArg, NULL},
- X {"-wlevel", "warnLevel", XrmoptionSepArg, NULL},
- X {"-wp", "warnProg", XrmoptionSepArg, NULL},
- X};
- Xstatic Arg formargs[] = {
- X {XtNdefaultDistance, 1}, /* Spacing */
- X {XtNresizable, TRUE }, /* Resizable */
- X};
- X
- Xmain (argc, argv)
- X
- Xint argc;
- Xchar **argv;
- X
- X{
- X Widget toplevel;
- X Widget form;
- X Widget pane = NULL;
- X int i;
- X int n;
- X Arg args[10];
- X XtAppContext appcon;
- X String mbtrans =
- X "<EnterWindow>: highlight()\n\
- X <LeaveWindow>: reset()\n\
- X <BtnDown>: set() notify() PopupMenu()";
- X XtTranslations mbtt;
- X Widget *lw; /* Last column or row of widgets */
- X int numwgt;
- X
- X progname = argv[0];
- X toplevel = XtAppInitialize (&appcon, "XMeter", options,
- X XtNumber (options), &argc, argv, NULL, NULL, ZERO);
- X XtGetApplicationResources (toplevel, NULL, application_resources,
- X XtNumber (application_resources), NULL, 0);
- X form = XtCreateManagedWidget ("form", formWidgetClass, toplevel,
- X formargs, XtNumber (formargs));
- X if (argc < 2)
- X usage ();
- X if (strcmp ("-v", argv[1]) == 0)
- X printversion ();
- X init (toplevel, &lw);
- X createmenus (form);
- X mbtt = XtParseTranslationTable (mbtrans);
- X /*
- X * Each meter consists of a paned widget, each paned widget has two
- X * children, which are a menubutton widget and stripchart widget.
- X * The following loop creates and initializes the appropriate widgets.
- X */
- X for (i = 1, numwgt = 0; i < argc; i++, numwgt++) {
- X meterlist = initmeter (meterlist, &i, argc, argv);
- X /*
- X * Create paned widget.
- X */
- X n = 0;
- X if (columns > 0) { /* Locate pane in form ... */
- X XtSetArg (args[n], XtNfromVert, lw[numwgt % columns]); n++;
- X if (numwgt % columns != 0) {
- X XtSetArg (args[n], XtNfromHoriz, pane); n++;
- X }
- X } else {
- X XtSetArg (args[n], XtNfromHoriz, lw[numwgt % rows]); n++;
- X if (numwgt % rows != 0) {
- X XtSetArg (args[n], XtNfromVert, pane); n++;
- X }
- X }
- X XtSetArg (args[n], XtNborder, bd[OK]); n++;
- X XtSetArg (args[n], XtNinternalBorderColor, ibd[OK]); n++;
- X pane = XtCreateManagedWidget (meterlist->sh->name, panedWidgetClass,
- X form, args, n);
- X lw[numwgt % (columns > 0 ? columns : rows)] = pane;
- X meterlist->pdwidget = pane;
- X /*
- X * Create menubutton widget.
- X */
- X n = 0;
- X XtSetArg (args[n], XtNshowGrip, XtEno); n++;
- X XtSetArg (args[n], XtNlabel, meterlist->label); n++;
- X XtSetArg (args[n], XtNbackground, lback[OK]); n++;
- X XtSetArg (args[n], XtNforeground, lfore[OK]); n++;
- X XtSetArg (args[n], XtNmenuName, STATMENU); n++;
- X XtSetArg (args[n], XtNtranslations, mbtt); n++;
- X meterlist->mbwidget = XtCreateManagedWidget ("menu",
- X menuButtonWidgetClass, pane, args, n);
- X XtRemoveAllCallbacks (meterlist->mbwidget, XtNcallback);
- X XtAddCallback (meterlist->mbwidget, XtNcallback, selecthost, meterlist);
- X /*
- X * Create stripchart widget.
- X */
- X n = 0;
- X XtSetArg (args[n], XtNfromVert, meterlist->mbwidget); n++;
- X XtSetArg (args[n], XtNresizable, TRUE); n++;
- X XtSetArg (args[n], XtNbackground, back[OK]); n++;
- X XtSetArg (args[n], XtNforeground, fore[OK]); n++;
- X XtSetArg (args[n], XtNhighlight, hl[OK]); n++;
- X meterlist->scwidget = XtCreateManagedWidget ("load",
- X stripChartWidgetClass, pane, args, n);
- X XtRemoveAllCallbacks (meterlist->scwidget, XtNgetValue);
- X XtAddCallback (meterlist->scwidget, XtNgetValue, getstatus, meterlist);
- X }
- X free (lw);
- X signal (SIGCHLD, freechild); /* Clean up after our children */
- X XtRealizeWidget (toplevel);
- X setokbackgrounds (XtDisplay (toplevel), XtScreen (toplevel));
- X XtAppMainLoop (appcon);
- X}
- X
- Xusage ()
- X
- X{
- X int i;
- X
- X fprintf (stderr, "Usage: %s [toolkit options] [options] [stat] host ...\n",
- X progname);
- X fprintf (stderr, " Options are:");
- X for (i = 0; i < XtNumber (options); i++) {
- X if (i % 8 == 0)
- X fprintf (stderr, "\n ");
- X else
- X fprintf (stderr, ", ");
- X fprintf (stderr, "%s", options[i].option);
- X }
- X fprintf (stderr, ", -v\n Stats to watch are:");
- X for (i = 0; i < MAXSTAT; i++) {
- X if (i % 8 == 0)
- X fprintf (stderr, "\n ");
- X else
- X fprintf (stderr, ", ");
- X fprintf (stderr, "-%s", sd[i].name);
- X }
- X fprintf (stderr, "\n");
- X exit (1);
- X}
- X
- X/*
- X * printversion - Print version number and exit.
- X */
- Xprintversion ()
- X
- X{
- X printf ("XMeter version %d.%d\n", MAJORVERSION, PATCHLEVEL);
- X exit (0);
- X}
- X
- X/*
- X * init - Initialze various globals.
- X */
- Xinit (toplevel, lw)
- X
- XWidget toplevel;
- XWidget **lw;
- X
- X{
- X int i;
- X Window rw;
- X int x;
- X int y;
- X int bwidth;
- X int depth;
- X
- X ptto.tv_sec = timeout;
- X tto.tv_sec = timeout * retries;
- X if (columns <= 0 && rows <= 0)
- X columns = 1;
- X if (columns > 0) {
- X if ((*lw = (Widget *) calloc (columns, sizeof (Widget))) == NULL)
- X fatal ("lw");
- X } else
- X if ((*lw = (Widget *) calloc (rows, sizeof (Widget))) == NULL)
- X fatal ("lw");
- X for (i = 0; i < MAXBACKS; i++)
- X if (bitmap[i].bm != bitmapdef) /* Get bitmap dimensions */
- X XGetGeometry (XtDisplay (toplevel), bitmap[i].bm, &rw, &x, &y,
- X &bitmap[i].w, &bitmap[i].h, &bwidth, &depth);
- X}
- X
- X/*
- X * createmenus - Create menus used by each meter. Currently there's just
- X * one which consists of the stats that can be monitored.
- X */
- Xcreatemenus (parent)
- X
- XWidget parent;
- X
- X{
- X int i;
- X int n;
- X Widget menu;
- X Widget me;
- X Arg args[10];
- X
- X menu = XtCreatePopupShell (STATMENU, simpleMenuWidgetClass, parent,
- X NULL, ZERO);
- X for (i = 0; i < MAXSTAT; i++) {
- X n = 0;
- X XtSetArg (args[n], XtNlabel, sd[i].name); n++;
- X me = XtCreateManagedWidget (sd[i].name, smeBSBObjectClass, menu,
- X args, n);
- X XtRemoveAllCallbacks (me, XtNcallback);
- X XtAddCallback (me, XtNcallback, changestat, i);
- X }
- X}
- X
- X/*
- X * setokbackgrounds - Set initial background pixmaps. Can't do this
- X * when the stripchart widgets are created as they have to be
- X * realized apparently before the pixmaps can be created.
- X */
- Xsetokbackgrounds (d, s)
- X
- XDisplay *d;
- XScreen *s;
- X
- X{
- X METER *h;
- X int n;
- X Arg args[10];
- X
- X if (bitmap[OK].bm != bitmapdef) {
- X for (h = meterlist; h; h = h->nxt) {
- X h->pm = XmuCreatePixmapFromBitmap (d, XtWindow (h->scwidget),
- X bitmap[OK].bm,
- X bitmap[OK].w, bitmap[OK].h,
- X DefaultDepthOfScreen (s),
- X fore[OK],
- X back[OK]);
- X n = 0;
- X XtSetArg (args[n], XtNbackgroundPixmap, h->pm); n++;
- X XtSetValues (h->scwidget, args, n);
- X }
- X }
- X}
- X
- X/*
- X * freechild - Clean up child processes.
- X */
- Xfreechild ()
- X
- X{
- X int status;
- X int pid;
- X METER *h;
- X
- X pid = wait (&status);
- X for (h = meterlist; h; h = h->nxt)
- X if (h->sh->pid == pid) { /* Start updating host again */
- X h->sh->pid = -1;
- X break;
- X }
- X}
- X
- X/*
- X * getstatus - Get status from remote host, update meter appropriately,
- X * including changing colors, background pixmap and label if necessary.
- X */
- Xgetstatus (w, h, data)
- X
- XWidget w;
- XMETER *h;
- Xchar *data;
- X
- X{
- X int l;
- X int n;
- X int s;
- X register SHMETER *sh;
- X Arg args[10];
- X
- X sh = h->sh;
- X if (h->oldstate == FATAL && sh->pid != -1) /* Ignore dead hosts */
- X return;
- X if (h->oldjumpscroll) { /* Restore old jumpscroll value */
- X n = 0;
- X XtSetArg (args[n], XtNjumpScroll, h->oldjumpscroll); n++;
- X XtSetValues (h->scwidget, args, n);
- X h->oldjumpscroll = 0;
- X }
- X s = state (l = getmeter (h), h);
- X *(double *) data = s == FATAL ? 0.0 : (double) l / sd[h->stat].scale;
- X if (s != h->oldstate) {
- X if (bitmap[h->oldstate].bm != bitmapdef)
- X XFreePixmap (XtDisplay (w), h->pm);
- X n = 0; /* Update stripchart widget */
- X XtSetArg (args[n], XtNbackground, back[s]); n++;
- X XtSetArg (args[n], XtNforeground, fore[s]); n++;
- X XtSetArg (args[n], XtNhighlight, hl[s]); n++;
- X if (bitmap[s].bm != bitmapdef) {
- X h->pm = XmuCreatePixmapFromBitmap (XtDisplay (w),
- X XtWindow (w),
- X bitmap[s].bm,
- X bitmap[s].w, bitmap[s].h,
- X DefaultDepthOfScreen(XtScreen(w)),
- X fore[s],
- X back[s]);
- X XtSetArg (args[n], XtNbackgroundPixmap, h->pm); n++;
- X } else if (bitmap[h->oldstate].bm != bitmapdef) {
- X XtSetArg (args[n], XtNbackgroundPixmap, XtUnspecifiedPixmap); n++;
- X }
- X XtSetValues (w, args, n);
- X n = 0; /* Update menubutton widget */
- X XtSetArg (args[n], XtNbackground, lback[s]); n++;
- X XtSetArg (args[n], XtNforeground, lfore[s]); n++;
- X if (s == FATAL || h->oldstate == FATAL) {
- X sprintf (h->label, "%s %s", sh->name,
- X s == FATAL ? DMSG : sd[h->stat].name);
- X XtSetArg (args[n], XtNlabel, h->label); n++;
- X }
- X XtSetValues (h->mbwidget, args, n);
- X n = 0; /* Update paned widget */
- X XtSetArg (args[n], XtNborder, bd[s]); n++;
- X XtSetArg (args[n], XtNinternalBorderColor, ibd[s]); n++;
- X XtSetValues (h->pdwidget, args, n);
- X if (prog[s])
- X runprog (h, s);
- X if (s == FATAL)
- X sh->pid = waitforhost (h);
- X }
- X h->oldstate = s;
- X}
- X
- X/*
- X * waitforhost - Fork process which will wait for host to come back up.
- X */
- Xint waitforhost (h)
- X
- XMETER *h;
- X
- X{
- X int pid;
- X
- X if (pid = fork ())
- X return (pid);
- X while (1) {
- X sleep (10);
- X if (getport (h) >= 0)
- X exit (0);
- X }
- X}
- X
- X/*
- X * runprog - Run user specified alert program.
- X */
- Xrunprog (h, s)
- X
- XMETER *h;
- Xint s;
- X
- X{
- X char oldstate[4];
- X char state[4];
- X
- X sprintf (oldstate, "%d", h->oldstate);
- X sprintf (state, "%d", s);
- X if (vfork ())
- X return; /* Parent just returns */
- X execlp (prog[s], prog[s], oldstate, state, h->sh->name, NULL);
- X fatal (prog[s]);
- X}
- X
- X/*
- X * selecthost - Select host for next changestat().
- X */
- Xselecthost (w, h, data)
- X
- XWidget w;
- XMETER *h;
- Xchar *data;
- X
- X{
- X selected = h;
- X}
- X
- X/*
- X * changestat - Change statistic we're looking at. To clear the stripchart
- X * it's necessary to poke the "interval" field in the StripChartWidget
- X * structure, and then set "jumpScroll" to the width of the stripchart.
- X * jumpScroll is saved here and restored in getstatus().
- X */
- X#include <X11/IntrinsicP.h>
- X#include <X11/Xaw/StripCharP.h>
- Xchangestat (w, statidx, data)
- X
- XWidget w;
- Xint statidx;
- Xchar *data;
- X
- X{
- X int n;
- X Arg args[10];
- X int width;
- X
- X selected->stat = statidx;
- X sprintf (selected->label, "%s %s", selected->sh->name,
- X sd[statidx].name);
- X n = 0;
- X XtSetArg (args[n], XtNlabel, selected->label); n++;
- X XtSetValues (selected->mbwidget, args, n);
- X n = 0;
- X XtSetArg (args[n], XtNwidth, &width); n++;
- X XtSetArg (args[n], XtNjumpScroll, &selected->oldjumpscroll); n++;
- X XtGetValues (selected->scwidget, args, n);
- X n = 0;
- X XtSetArg (args[n], XtNjumpScroll, width); n++;
- X XtSetValues (selected->scwidget, args, n);
- X ((StripChartWidget) selected->scwidget)->strip_chart.interval = width;
- X}
- X
- X/*
- X * state - Return state of current stat.
- X */
- Xint state (l, h)
- X
- Xint l;
- XMETER *h;
- X
- X{
- X if (l < 0)
- X return (FATAL);
- X else if (l < warnLevel * sd[h->stat].scale)
- X return (OK);
- X else if (l < errorLevel * sd[h->stat].scale)
- X return (WARN);
- X else
- X return (ERROR);
- X}
- X
- X/*
- X * The following functions return the value of the specified stat, which
- X * is normally computed by taking the difference between the current
- X * value and the previous value, and dividing by the update interval in
- X * order to get the current rate.
- X */
- X#define DIF(m,fld) (m->sh->st[m->sh->idx].fld - \
- X m->sh->st[m->sh->idx ^ 1].fld)
- X
- Xint fcoll (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, if_collisions) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fcpu (h)
- X
- XMETER *h;
- X
- X{
- X int i;
- X int t;
- X int d[CPUSTATES];
- X
- X for (t = 0, i= 0; i < CPUSTATES; i++)
- X t += (d[i] = DIF (h, cp_time[i]));
- X return (t ? (100 * (d[CP_USER]+d[CP_NICE]+d[CP_SYS])) / t : 0);
- X}
- X
- Xint fierr (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, if_ierrors) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fintr (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, v_intr) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fipkt (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, if_ipackets) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fload (h)
- X
- XMETER *h;
- X
- X{
- X return (h->sh->st[h->sh->idx].avenrun[0]);
- X}
- X
- Xint foerr (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, if_oerrors) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fopkt (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, if_opackets) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fpage (h)
- X
- XMETER *h;
- X
- X{
- X return ((DIF (h, v_pgpgin) + DIF (h, v_pgpgout)) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fpgpgin (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, v_pgpgin) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fpgpgout (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, v_pgpgout) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fpswpin (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, v_pswpin) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fpswpout (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, v_pswpout) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fswt (h)
- X
- XMETER *h;
- X
- X{
- X return (DIF (h, v_swtch) / DIF (h, curtime.tv_sec));
- X}
- X
- Xint fsys (h)
- X
- XMETER *h;
- X
- X{
- X int i;
- X int t;
- X int d[CPUSTATES];
- X
- X for (t = 0, i= 0; i < CPUSTATES; i++)
- X t += (d[i] = DIF (h, cp_time[i]));
- X return (t ? (100 * d[CP_SYS]) / t : 0);
- X}
- X
- Xint fuser (h)
- X
- XMETER *h;
- X
- X{
- X int i;
- X int t;
- X int d[CPUSTATES];
- X
- X for (t = 0, i= 0; i < CPUSTATES; i++)
- X t += (d[i] = DIF (h, cp_time[i]));
- X return (t ? (100 * (d[CP_USER] + d[CP_NICE])) / t : 0);
- X}
- X
- X/*
- X * getmeter - Executes rstat(3) call to read statistics for specified host.
- X * I do all the rpc junk myself so that I have better control over timeouts
- X * than rstat(3) gives me. If we're watching multiple stats
- X * on the same host I only do one rstat(3) call (refcnt and curcnt are
- X * used for this).
- X */
- Xint getmeter (h)
- X
- Xregister METER *h;
- X
- X{
- X enum clnt_stat cs;
- X register SHMETER *sh;
- X int p;
- X
- X sh = h->sh;
- X if (sh->curcnt >= sh->refcnt)
- X sh->curcnt = 0;
- X if (!sh->curcnt++) {
- X if (sh->clnt == NULL) {
- X if ((p = getport (h)) < 0)
- X return (-1);
- X sh->addr.sin_port = htons (p);
- X sh->s = RPC_ANYSOCK;
- X if (!(sh->clnt = clntudp_create(&sh->addr, RSTATPROG, RSTATVERS_TIME,
- X ptto, &sh->s)))
- X return (-1);
- X sh->first = 1;
- X sh->idx = 0;
- X } else {
- X sh->first = 0;
- X sh->idx ^= 1;
- X }
- X cs = clnt_call (sh->clnt, RSTATPROC_STATS, xdr_void, 0, xdr_statstime,
- X &sh->st[sh->idx], tto);
- X if (cs != RPC_SUCCESS) {
- X clnt_destroy (sh->clnt);
- X close (sh->s); /* Some clnt_destroy's don't do this */
- X sh->clnt = NULL;
- X return (-1);
- X }
- X }
- X return (sh->first ? 0 :
- X sh->clnt == NULL ? -1 : (sd[h->stat].val) (h));
- X}
- X
- X/*
- X * getport - Get port rstatd is listening on.
- X */
- Xint getport (h)
- X
- XMETER *h;
- X
- X{
- X CLIENT *c;
- X enum clnt_stat cs;
- X static struct pmap pm = {RSTATPROG, RSTATVERS_TIME, IPPROTO_UDP, 0};
- X short p;
- X register SHMETER *sh;
- X
- X sh = h->sh;
- X sh->s = RPC_ANYSOCK;
- X sh->addr.sin_port = htons (PMAPPORT);
- X if (!(c = clntudp_create (&sh->addr, PMAPPROG, PMAPVERS, ptto, &sh->s)))
- X return (-1);
- X cs = clnt_call (c, PMAPPROC_GETPORT, xdr_pmap, &pm, xdr_u_short, &p, tto);
- X clnt_destroy (c);
- X close (sh->s); /* Some clnt_destroy's don't do this */
- X return (cs == RPC_SUCCESS ? p : -1);
- X}
- X
- X/*
- X * initmeter - Fill in METER and SHMETER structures for this stat.
- X */
- XMETER *initmeter (meterlist, idx, argc, argv)
- X
- XMETER *meterlist;
- Xint *idx;
- Xint argc;
- Xchar **argv;
- X
- X{
- X register METER *h;
- X register SHMETER *sh;
- X struct hostent *he;
- X int i;
- X char *cp;
- X
- X /*
- X * Create and fill in METER struct.
- X */
- X if (!(h = (METER *) malloc (sizeof (METER))))
- X fatal ("METER");
- X h->nxt = meterlist;
- X cp = (argv[*idx][0] == '-') ? &argv[*idx][1] : defstat;
- X for (i = 0; i < MAXSTAT; i++)
- X if (strcmp (cp, sd[i].name) == 0) {
- X h->stat = i;
- X break;
- X }
- X if ((cp != defstat) && (++(*idx) == argc || i >= MAXSTAT))
- X usage ();
- X if ((he = gethostbyname (argv[*idx])) == NULL)
- X fatal (argv[*idx]);
- X if (shortname)
- X if (cp = index (he->h_name, '.'))
- X *cp = '\0';
- X if (!(h->label = malloc (strlen (he->h_name) + 2 + MAXSTATNAME)))
- X fatal ("label");
- X sprintf (h->label, "%s %s", he->h_name, sd[h->stat].name);
- X h->oldstate = OK;
- X h->oldjumpscroll = 0;
- X /*
- X * If we're already looking at this host then just point h->sh at
- X * existing structure and we're done.
- X */
- X for (sh = shmeters; sh; sh = sh->nxt)
- X if (strcmp (sh->name, he->h_name) == 0) {
- X h->sh = sh;
- X sh->refcnt++; /* Count how many references */
- X return (h);
- X }
- X /*
- X * Not looking at this host yet, create and fill in SHMETER struct.
- X */
- X if (!(sh = (SHMETER *) malloc (sizeof (SHMETER))))
- X fatal ("SHMETER");
- X sh->nxt = shmeters; /* Save this struct in linked list */
- X shmeters = sh;
- X h->sh = sh;
- X if (!(sh->name = malloc (strlen (he->h_name) + 1)))
- X fatal ("name");
- X strcpy (sh->name, he->h_name);
- X bcopy (he->h_addr, &sh->addr.sin_addr, he->h_length);
- X sh->addr.sin_family = AF_INET;
- X sh->clnt = NULL;
- X sh->refcnt = 1;
- X sh->curcnt = 0;
- X sh->pid = -1;
- X return (h);
- X}
- X
- Xfatal (m)
- X
- Xchar *m;
- X
- X{
- X perror (m);
- X exit (1);
- X}
- END_OF_FILE
- if test 33499 -ne `wc -c <'xmeter.c'`; then
- echo shar: \"'xmeter.c'\" unpacked with wrong size!
- fi
- # end of 'xmeter.c'
- fi
- if test -f 'xmeter.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xmeter.man'\"
- else
- echo shar: Extracting \"'xmeter.man'\" \(14019 characters\)
- sed "s/^X//" >'xmeter.man' <<'END_OF_FILE'
- X.TH XMETER 1 "14 August 1989" "X Version 11"
- X.SH NAME
- Xxmeter - rstat display for X
- X.SH SYNOPSIS
- X.B xmeter
- X[-\fItoolkitoption\fP ...] [-\fIoption\fP ...] [-\fIstat\fP] hosts ...
- X.SH DESCRIPTION
- X.I Xmeter
- Xdisplays a periodically updating histogram of the system statistics
- Xgathered by rstat(3) for the specified hosts. Meters can be
- Xdisplayed in a vertical, horizontal or rectangular arrangement. As
- Xstatistics range between 4 user defineable levels (OK, WARN, ERROR
- Xor FATAL), the background, foreground, highlight, border and internal
- Xborder colors and the background bitmap of each meter can be changed.
- X.LP
- X.I Xmeter
- Xuses the StripChart widget of the Athena Widget Set to graph each
- Xstatistic. StripCharts automatically scale the graph as the value
- Xvaries, by drawing a number of horizontal lines across the StripChart.
- XEach line represents an increment of a user settable value. For
- Xexample, if the statistic being graphed is number of pages paged in
- Xper second, and the scale is set to 10, then each horizontal line
- Xwould represent 10 pages per second. Each time a graph is updated,
- X.I xmeter
- Xwill examine the current value of the statistic and the current scale,
- Xas the number of scale lines increases above
- X.I wlevel
- Xand
- X.I elevel
- Xthe background colors and bitmaps of each graph are modified as specified.
- X.LP
- XThe statistic being graphed may be modified while
- X.I xmeter
- Xis running by moving the mouse cursor into the label part of a graph,
- Xclicking any mouse button, and sliding down to the desired stat.
- X.SH OPTIONS
- X.PP
- X.I Xmeter
- Xaccepts all of the standard X Toolkit command line options along with the
- Xfollowing additional options:
- X.PP
- X.TP 8
- X.B \-cols \fIcols\fP
- XThis option specifies the number of columns the meters should be
- Xdisplayed in. If both
- X.I cols
- Xand
- X.I rows
- Xare specified,
- X.I cols
- Xtakes precedence. The default is 1 column.
- X.PP
- X.TP 8
- X.B \-ebd \fIcolor\fP
- XSet error level border color.
- X.PP
- X.TP 8
- X.B \-ebg \fIcolor\fP
- XSet error level background color.
- X.PP
- X.TP 8
- X.B \-efg \fIcolor\fP
- XSet error level foreground color.
- X.PP
- X.TP 8
- X.B \-ehl \fIcolor\fP
- XSet error level highlight color.
- X.PP
- X.TP 8
- X.B \-eibd \fIcolor\fP
- XSet error level internal border color.
- X.PP
- X.TP 8
- X.B \-elevel \fIinteger\fP
- XThis option specifies the level at which the background color is changed
- Xto ebg. The default is 6.
- X.PP
- X.TP 8
- X.B \-ep \fIprogram\fP
- X.I program
- Xshould be the name of a program to be invoked when the meter enters the
- Xerror state.
- X.I program
- Xwill be passed 3 arguments, oldstate, newstate and the hostname being
- Xmonitored. Oldstate and newstate will be integers ranging from 0 to
- X3, corresponding to levels OK, WARN, ERROR and FATAL.
- X.PP
- X.TP 8
- X.B \-fbd \fIcolor\fP
- XSet fatal level border color.
- X.PP
- X.TP 8
- X.B \-fbg \fIcolor\fP
- XSet fatal level background color.
- X.PP
- X.TP 8
- X.B \-ffg \fIcolor\fP
- XSet fatal level foreground color.
- X.PP
- X.TP 8
- X.B \-fhl \fIcolor\fP
- XSet fatal level highlight color.
- X.PP
- X.TP 8
- X.B \-fibd \fIcolor\fP
- XSet fatal level internal border color.
- X.PP
- X.TP 8
- X.B \-fp \fIprogram\fP
- X.I program
- Xshould be the name of a program to be invoked when the monitored host is
- Xdown.
- X.I program
- Xwill be passed 3 arguments, oldstate, newstate and the hostname being
- Xmonitored. Oldstate and newstate will be integers ranging from 0 to
- X3, corresponding to levels OK, WARN, ERROR and FATAL.
- X.PP
- X.TP 8
- X.B \-h \fIpixels\fP
- XThis option specifies the height of each chart
- X.I xmeter
- Xwill display. The default is 80.
- X.PP
- X.TP 8
- X.B \-lebg \fIcolor\fP
- XSet error level background color in menubutton.
- X.PP
- X.TP 8
- X.B \-lefg \fIcolor\fP
- XSet error level foreground color in menubutton.
- X.PP
- X.TP 8
- X.B \-lfbg \fIcolor\fP
- XSet fatal level background color in menubutton.
- X.PP
- X.TP 8
- X.B \-lffg \fIcolor\fP
- XSet fatal level foreground color in menubutton.
- X.PP
- X.TP 8
- X.B \-lobg \fIcolor\fP
- XSet ok level background color in menubutton.
- X.PP
- X.TP 8
- X.B \-lofg \fIcolor\fP
- XSet ok level foreground color in menubutton.
- X.PP
- X.TP 8
- X.B \-lwbg \fIcolor\fP
- XSet warn level background color in menubutton.
- X.PP
- X.TP 8
- X.B \-lwfg \fIcolor\fP
- XSet warn level foreground color in menubutton.
- X.PP
- X.TP 8
- X.B \-obd \fIcolor\fP
- XSet ok level border color.
- X.PP
- X.TP 8
- X.B \-obg \fIcolor\fP
- XSet ok level background color.
- X.PP
- X.TP 8
- X.B \-ofg \fIcolor\fP
- XSet ok level foreground color.
- X.PP
- X.TP 8
- X.B \-ohl \fIcolor\fP
- XSet ok level highlight color.
- X.PP
- X.TP 8
- X.B \-oibd \fIcolor\fP
- XSet ok level internal border color.
- X.PP
- X.TP 8
- X.B \-op \fIprogram\fP
- X.I program
- Xshould be the name of a program to be invoked when the meter enters WARN
- Xstate.
- X.I program
- Xwill be passed 3 arguments, oldstate, newstate and the hostname being
- Xmonitored. Oldstate and newstate will be integers ranging from 0 to
- X3, corresponding to levels OK, WARN, ERROR and FATAL.
- X.PP
- X.TP 8
- X.B \-rows \fIrows\fP
- XThis option specifies the number of rows the meters should be
- Xdisplayed in. If both
- X.I cols
- Xand
- X.I rows
- Xare specified,
- X.I cols
- Xtakes precedence. The default is 1 column.
- X.PP
- X.TP 8
- X.B \-rt \fIretries\fP
- XThis option specifies the number of times to retry failed RPC calls.
- XThe default is 2.
- X.PP
- X.TP 8
- X.B \-scoll \fIinteger\fP
- XSet scale for collisions. The default is 1.
- X.PP
- X.TP 8
- X.B \-scpu \fIinteger\fP
- XSet scale for cpu time. The default is 20.
- X.PP
- X.TP 8
- X.B \-sierr \fIinteger\fP
- XSet scale for input errors. The default is 1.
- X.PP
- X.TP 8
- X.B \-sintr \fIinteger\fP
- XSet scale for interrupts. The default is 50.
- X.PP
- X.TP 8
- X.B \-sipkt \fIinteger\fP
- XSet scale for input packets. The default is 20.
- X.PP
- X.TP 8
- X.B \-sload \fIinteger\fP
- XSet scale for load average. The default is FSCALE (see param.h).
- X.PP
- X.TP 8
- X.B \-sn
- XIf specified strips off domain part of host name in menubuttons.
- X.PP
- X.TP 8
- X.B \-soerr \fIinteger\fP
- XSet scale for output errors. The default is 1.
- X.PP
- X.TP 8
- X.B \-sopkt \fIinteger\fP
- XSet scale for output packets. The default is 20.
- X.PP
- X.TP 8
- X.B \-spage \fIinteger\fP
- XSet scale for pages paged in and out. The default is 10.
- X.PP
- X.TP 8
- X.B \-spgpgin \fIinteger\fP
- XSet scale for pages paged in. The default is 10.
- X.PP
- X.TP 8
- X.B \-spgpgout \fIinteger\fP
- XSet scale for pages paged out. The default is 10.
- X.PP
- X.TP 8
- X.B \-spswpin \fIinteger\fP
- XSet scale for pages swapped in. The default is 1.
- X.PP
- X.TP 8
- X.B \-spswpout \fIinteger\fP
- XSet scale for pages swapped out. The default is 1.
- X.PP
- X.TP 8
- X.B \-sswt \fIinteger\fP
- XSet scale for context switches. The default is 30.
- X.PP
- X.TP 8
- X.B \-ssys \fIinteger\fP
- XSet scale for sys time. The default is 20.
- X.PP
- X.TP 8
- X.B \-suser \fIinteger\fP
- XSet scale for user time. The default is 20.
- X.PP
- X.TP 8
- X.B \-to \fIseconds\fP
- XThis option specifies the timeout for RPC calls. The default is 5 seconds.
- X.PP
- X.TP 8
- X.B \-update \fIseconds\fP
- XThis option specifies the frequency in seconds at which
- X.I xmeter
- Xupdates its display. The minimum amount of time allowed between updates
- Xis 5 seconds. The default is 60 seconds.
- X.PP
- X.TP 8
- X.B \-v
- XPrint version number and exit.
- X.PP
- X.TP 8
- X.B \-w \fIpixels\fP
- XThis option specifies the width of each chart
- X.I xmeter
- Xwill display. The default is 80.
- X.PP
- X.TP 8
- X.B \-wbd \fIcolor\fP
- XSet warn level border color.
- X.PP
- X.TP 8
- X.B \-wbg \fIcolor\fP
- XSet warn level background color.
- X.PP
- X.TP 8
- X.B \-wfg \fIcolor\fP
- XSet warn level foreground color.
- X.PP
- X.TP 8
- X.B \-whl \fIcolor\fP
- XSet warn level highlight color.
- X.PP
- X.TP 8
- X.B \-wibd \fIcolor\fP
- XSet warn level internal border color.
- X.PP
- X.TP 8
- X.B \-wlevel \fIinteger\fP
- XThis option specifies the level at which the background color is changed
- Xto wbg. The default is 3.
- X.PP
- X.TP 8
- X.B \-wp \fIprogram\fP
- X.I program
- Xshould be the name of a program to be invoked when the meter enters
- XWARN state.
- X.I program
- Xwill be passed 3 arguments, oldstate, newstate and the hostname being
- Xmonitored. Oldstate and newstate will be integers ranging from 0 to
- X3, corresponding to levels OK, WARN, ERROR and FATAL.
- X.SH STATISTICS
- X.PP
- X.TP 8
- X.B \-coll
- XGraph number of collisions per second.
- X.PP
- X.TP 8
- X.B \-cpu
- XGraph percentage of non idle time for the specified host.
- X.PP
- X.TP 8
- X.B \-ierr
- XGraph number of input errors per second.
- X.PP
- X.TP 8
- X.B \-intr
- XGraph number of interrupts per second.
- X.PP
- X.TP 8
- X.B \-ipkt
- XGraph number of input packets per second.
- X.PP
- X.TP 8
- X.B \-load
- XGraph 1 minute load average.
- X.PP
- X.TP 8
- X.B \-oerr
- XGraph number of output errors per second.
- X.PP
- X.TP 8
- X.B \-opkt
- XGraph number of output packets per second.
- X.PP
- X.TP 8
- X.B \-page
- XSum of pgpgin and pgpgout values.
- X.PP
- X.TP 8
- X.B \-pgpgin
- XGraph number of pages paged in per second.
- X.PP
- X.TP 8
- X.B \-pgpgout
- XGraph number of pages paged out per second.
- X.PP
- X.TP 8
- X.B \-pswpin
- XGraph number of swapins per second.
- X.PP
- X.TP 8
- X.B \-pswpout
- XGraph number of swapouts per second.
- X.PP
- X.TP 8
- X.B \-swt
- XGraph number of context switches per second.
- X.PP
- X.TP 8
- X.B \-sys
- XGraph percentage of system time for the specified host.
- X.PP
- X.TP 8
- X.B \-user
- XGraph percentage of user time for the specified host.
- X.SH "WIDGET HIERARCHY"
- XThe widget hierarchy for
- X.I xmeter
- Xis given below. Class names are given first, followed by instance
- Xnames.
- X.sp
- X.nf
- XXMeter xmeter
- X Form form
- X SimpleMenu statmenu
- X SmeBSB <stat>
- X Paned <hostname>
- X MenuButton menu
- X StripChart load
- X.SH "RESOURCES"
- XThe following resources are defined. Resource instance names
- Xare specified first, followed by class name.
- X.PP
- X.TP 8
- X.B columns Columns
- XSet number of columns of display.
- X.PP
- X.TP 8
- X.B defStat DefStat
- XDefault statistic to graph, the default is \fBload\fP.
- X.PP
- X.TP 8
- X.B errorBack Background
- XError level background color.
- X.PP
- X.TP 8
- X.B errorBd Foreground
- XError level border color.
- X.PP
- X.TP 8
- X.B errorBitmap Bitmap
- XError level background bitmap.
- X.PP
- X.TP 8
- X.B errorFore Foreground
- XError level foreground color.
- X.PP
- X.TP 8
- X.B errorHl Foreground
- XError level highlight color.
- X.PP
- X.TP 8
- X.B errorIbd Foreground
- XError level internal border color.
- X.PP
- X.TP 8
- X.B errorLevel ErrorLevel
- XWhen a statistic is above this value colors and bitmaps are
- Xset to the appropriate error level value.
- X.PP
- X.TP 8
- X.B errorProg Program
- XProgram to be invoked when a meter enters error state.
- X.PP
- X.TP 8
- X.B fatalBack Background
- XBackground color of dead hosts.
- X.PP
- X.TP 8
- X.B fatalBd Foreground
- XBorder color of dead hosts.
- X.PP
- X.TP 8
- X.B fatalBitmap Bitmap
- XBackground bitmap of dead hosts.
- X.PP
- X.TP 8
- X.B fatalFore Foreground
- XForeground color of dead hosts.
- X.PP
- X.TP 8
- X.B fatalHl Foreground
- XHighlight color of dead hosts.
- X.PP
- X.TP 8
- X.B fatalIbd Foreground
- XInternal border color of dead hosts.
- X.PP
- X.TP 8
- X.B fatalProg Program
- XProgram to be invoked when a meter enters fatal state.
- X.PP
- X.TP 8
- X.B lErrorBack Background
- XError level background color of menubutton widget.
- X.PP
- X.TP 8
- X.B lErrorFore Foreground
- XError level foreground color of menubutton widget.
- X.PP
- X.TP 8
- X.B lFatalBack Background
- XFatal level background color of menubutton widget.
- X.PP
- X.TP 8
- X.B lFatalFore Foreground
- XFatal level foreground color of menubutton widget.
- X.PP
- X.TP 8
- X.B lOkBack Background
- XOk level background color of menubutton widget.
- X.PP
- X.TP 8
- X.B lOkFore Foreground
- XOk level foreground color of menubutton widget.
- X.PP
- X.TP 8
- X.B lWarnBack Background
- XWarn level background color of menubutton widget.
- X.PP
- X.TP 8
- X.B lWarnFore Foreground
- XWarn level foreground color of menubutton widget.
- X.PP
- X.TP 8
- X.B okBack Background
- XOk level background color.
- X.PP
- X.TP 8
- X.B okBd Foreground
- XOk level border color.
- X.PP
- X.TP 8
- X.B okBitmap Bitmap
- XOk level background bitmap.
- X.PP
- X.TP 8
- X.B okFore Foreground
- XOk level foreground color.
- X.PP
- X.TP 8
- X.B okHl Foreground
- XOk level highlight color.
- X.PP
- X.TP 8
- X.B okIbd Foreground
- XOk level internal border color.
- X.PP
- X.TP 8
- X.B okProg Program
- XProgram to be invoked when a meter enters ok state.
- X.PP
- X.TP 8
- X.B retries Retries
- XNumber of retries for RPC calls.
- X.PP
- X.TP 8
- X.B rows Rows
- XNumber of rows to display.
- X.PP
- X.TP 8
- X.B scaleColl ScaleColl
- XScale for interface collisions.
- X.PP
- X.TP 8
- X.B scaleCpu ScaleCpu
- XScale for percentage cpu usage.
- X.PP
- X.TP 8
- X.B scaleIerr ScaleIerr
- XScale for interface input errors.
- X.PP
- X.TP 8
- X.B scaleIerr ScaleIntr
- XScale for interface interrupts.
- X.PP
- X.TP 8
- X.B scaleIpkt ScaleIpkt
- XScale for interface input packets.
- X.PP
- X.TP 8
- X.B scaleLoad ScaleLoad
- XScale for load average.
- X.PP
- X.TP 8
- X.B scaleOerr ScaleOerr
- XScale for interface output errors.
- X.PP
- X.TP 8
- X.B scaleOpkt ScaleOpkt
- XScale for interface output packets.
- X.PP
- X.TP 8
- X.B scalePage ScalePage
- XScale for paging (sum of pageins and pageouts).
- X.PP
- X.TP 8
- X.B scalePgpgin ScalePgpgin
- XScale for pages paged in.
- X.PP
- X.TP 8
- X.B scalePgpgout ScalePgpgout
- XScale for pages paged out.
- X.PP
- X.TP 8
- X.B scalePswpin ScalePswpin
- XScale for swap ins.
- X.PP
- X.TP 8
- X.B scalePswpout ScalePswpout
- XScale for swap outs.
- X.PP
- X.TP 8
- X.B scaleSwt ScaleSwt
- XScale for context switches.
- X.PP
- X.TP 8
- X.B scaleSys ScaleSys
- XScale for percentage system time.
- X.PP
- X.TP 8
- X.B scaleUser ScaleUser
- XScale for percentage user time.
- X.PP
- X.TP 8
- X.B shortName ShortName
- XTrim domains off host names.
- X.PP
- X.TP 8
- X.B timeout Timeout
- XTimeout for RPC calls.
- X.PP
- X.TP 8
- X.B update Interval
- XInterval between updates.
- X.PP
- X.TP 8
- X.B warnBack Background
- XWarn level background color.
- X.PP
- X.TP 8
- X.B warnBd Foreground
- XWarn level border color.
- X.PP
- X.TP 8
- X.B warnBitmap Bitmap
- XWarn level Background bitmap.
- Xbelow ErrorLevel.
- X.PP
- X.TP 8
- X.B warnFore Foreground
- XWarn level foreground color.
- X.PP
- X.TP 8
- X.B warnHl Foreground
- XWarn level highlight color.
- X.PP
- X.TP 8
- X.B warnIbd Foreground
- XWarn level internal border.
- X.PP
- X.TP 8
- X.B warnLevel WarnLevel
- XWhen statistic is above this level and below ErrorLevel background colors
- Xand bitmaps are set to WarnBack and WarnBitmap.
- X.PP
- X.TP 8
- X.B warnProg Program
- XProgram to be invoked when a meter enters warn state.
- X.SH BUGS
- XWhen a host doesn't respond it can sometimes take awhile for the labels
- Xin the menubuttons to update.
- X.LP
- XIf a height for the meters is specified but not a width, the error
- X"Widget has zero width and/or height" is printed by the X toolkit.
- XThe converse is not true. I suspect the problem is in the Paned
- Xwidget but xmeter could be doing something wrong. The supplied
- Xapplication defaults file initializes both width and height, as long
- Xas this is installed there shouldn't be a problem unless the user
- Xexplicitly sets width to 0.
- X.SH AUTHOR
- XBob Schwartzkopf, The RAND Corporation. Based on xload from MIT.
- END_OF_FILE
- if test 14019 -ne `wc -c <'xmeter.man'`; then
- echo shar: \"'xmeter.man'\" unpacked with wrong size!
- fi
- # end of 'xmeter.man'
- fi
- if test -f 'XMeter.ad' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'XMeter.ad'\"
- else
- echo shar: Extracting \"'XMeter.ad'\" \(80 characters\)
- sed "s/^X//" >'XMeter.ad' <<'END_OF_FILE'
- XXMeter*Paned.Width: 80
- XXMeter*Paned.Height: 80
- XXMeter*StripChart.Interval: 60
- END_OF_FILE
- if test 80 -ne `wc -c <'XMeter.ad'`; then
- echo shar: \"'XMeter.ad'\" unpacked with wrong size!
- fi
- # end of 'XMeter.ad'
- fi
- echo shar: End of shell archive.
- exit 0
-
-
- --
- Dan Heller
- O'Reilly && Associates Z-Code Software Comp-sources-x:
- Senior Writer President comp-sources-x@uunet.uu.net
- argv@ora.com argv@zipcode.com
-